package ar.edu.phm.tpdos.observableByMixin;

import java.util.HashSet;
import java.util.Set;

import ar.edu.phm.tpdos.annotations.Validable;
import ar.edu.phm.tpdos.asignarAVariableValidador.ObjetoValidable;
import ar.edu.phm.tpdos.asignarAVariableValidador.Validador;

public aspect ObservableByMixinAspect {
	declare parents : @Validable * implements ObservableObject;

	pointcut asignacionMonitoreada(ObservableObject target, Object newValue) :  
	set(* *..*)
	&& args(newValue) 
	&& target(@Validable target)
	&& !withincode(*.new(..))
	&& within(@Validable *);

before(ObservableObject target, Object newValue): asignacionMonitoreada(target, newValue)  {
		String nombreVariable = thisJoinPoint.getSignature().getName();
		target.notificar(target, nombreVariable, newValue);
	}

after(ObservableObject target) : initialization(* ..*.new(..) ) && target(@Observable target) {
		target.init();
	}

	private transient Set<ObjetoValidable> ObservableObject.validadores;

	public void ObservableObject.init() {
		this.validadores = new HashSet<ObjetoValidable>();
	}

	public void ObservableObject.notificar(Object target, String nombreCampo,
			Object valor) {
		for (ObjetoValidable validable : validadores)
			validable.validar(target, nombreCampo, valor);
	}

	public void ObservableObject.agregarValidador(Object obj, String nombre,
			Validador<?> validador) {
		validadores.add(new ObjetoValidable(obj, nombre, validador));
	}

	public void ObservableObject.eliminarValidador(Validador<?> validador) {
		validadores.remove(validador);
	}
}
